package pl.jtb.ctl.tabory.dao.impl.mybatis.impl;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.log4j.Logger;

import pl.jtb.ctl.tabory.dao.api.services.ITripService;
import pl.jtb.ctl.tabory.dao.api.services.IVagonService;
import pl.jtb.ctl.tabory.dao.data.vo.TripVO;
import pl.jtb.ctl.tabory.dao.data.vo.VagonVO;
import pl.jtb.ctl.tabory.dao.impl.mybatis.base.BaseDaoService;
import pl.jtb.ctl.tabory.dao.impl.mybatis.servicemanager.ServiceManager;

public class TripServiceImpl extends BaseDaoService<TripVO> implements ITripService {

    private final static Logger logger = Logger.getLogger(TripServiceImpl.class);

    private final static String MAPPER = "pl.jtb.ctl.taboty.TripMapper";
    private final static String SQL_INSERT_TRIP = ".addTrip";
    private final static String SQL_GET_TRIP_BY_ID = ".selectTripById";
    private final static String SQL_GET_ALL_TRIPS = ".selectAllTrips";
    private final static String SQL_GET_TRIPS_FOR_COMPOSITION = ".selectTripsForComposition";
    private final static String SQL_UPDATE_TRIP = ".updateTrip";
    private final static String SQL_DELETE_TRIP = ".deleteTrip";
    private final static String SQL_GET_TRIPVALUES_FOR_TRIP = ".getTripValuesForTrip";
    private final static String SQL_GET_TRIPVALUES_FOR_VAGON = ".getTripValuesForVagon";
    private final static String SQL_ADD_TRIPVALUES = ".addTripValues";
    private final static String SQL_DROP_TRIPVALUES_FOR_COMPOSITION = ".dropTripValuesForComposition";
    private final static String SQL_DROP_TRIPVALUES_FOR_TRIP = ".dropTripValuesForTrip";

    public TripServiceImpl(SqlSessionFactory sqlSessionFactory) {
        super(sqlSessionFactory);
    }

    @Override
    public List<TripVO> getAllTrips() throws Exception {
        throw new UnsupportedOperationException("not yet implemented");
    }

    @SuppressWarnings("unchecked")
    @Override
    public List<TripVO> getTripsForComposition(Long compositionId) throws Exception {
        logger.debug("Getting Trips for composition with id: " + compositionId);
        List<TripVO> list = null;
        SqlSession session = null;
        IVagonService vagonService = ServiceManager.getInstance().getVagonService();
        try {
            list = selectList(MAPPER + SQL_GET_TRIPS_FOR_COMPOSITION, compositionId);
            session = sessionFactory.openSession();
            for (TripVO tripVO : list) {
                List<Map<String, Long>> selectList = (List<Map<String, Long>>) session.selectList(MAPPER + SQL_GET_TRIPVALUES_FOR_TRIP, tripVO.getId());
                List<VagonVO> listVagons = new ArrayList<VagonVO>();
                for (Map<String, Long> map : selectList) {
                    VagonVO vagon = vagonService.getVagon(map.get("VAGON_ID"));
                    listVagons.add(vagon);
                }
                tripVO.setListVagons(listVagons);
            }
            session.commit();
            session.close();
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            throw e;
        } finally {
            session.close();
        }
        if (list != null) {
            Collections.sort(list, new Comparator<TripVO>() {
                @Override
                public int compare(TripVO o1, TripVO o2) {
                    return o1.getDateFrom().compareTo(o2.getDateFrom());
                }
            });
        }
        return list;
    }

    @Override
    public void saveUpdateTrip(TripVO trip) throws Exception {
        logger.debug("Save/Update trip: " + trip);
        if (trip.getId() == null) {
            saveNewTrip(trip);
        } else {
            updateTrip(trip);
        }
    }

    @Override
    public void deleteTrip(TripVO trip) throws Exception {
        logger.debug("Deleting trip: " + trip);
        try {
            delete(MAPPER + SQL_DROP_TRIPVALUES_FOR_TRIP, trip.getId());
            delete(MAPPER + SQL_DELETE_TRIP, trip.getId());
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            throw e;
        }
    }

    private void saveNewTrip(TripVO trip) throws Exception {
        logger.debug("Saving new trip: " + trip);
        try {
            create(MAPPER + SQL_INSERT_TRIP, trip);
            for (VagonVO vagon : trip.getListVagons()) {
                Map<String, Object> mapTripValues = new HashMap<String, Object>();
                mapTripValues.put("tripId", trip.getId());
                mapTripValues.put("compositionId", trip.getComposition() == null ? null : trip.getComposition().getId());
                mapTripValues.put("vagonId", vagon.getId());
                create(MAPPER + SQL_ADD_TRIPVALUES, mapTripValues);
            }
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            throw e;
        }
    }

    private void updateTrip(TripVO trip) throws Exception {
        logger.debug("Updating trip " + trip);
        try {
            create(MAPPER + SQL_UPDATE_TRIP, trip);
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            throw e;
        }
    }

    @Override
    public TripVO getTrip(Long tripId) throws Exception {
        TripVO trip = null;
        try {
            trip = selectOne(MAPPER + SQL_GET_TRIP_BY_ID, tripId);
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            throw e;
        }
        return trip;
    }

    @SuppressWarnings("unchecked")
    @Override
    public List<TripVO> getTripsForVagon(Long vaognId) throws Exception {
        List<TripVO> result = new ArrayList<TripVO>();
        SqlSession session = null;
        try {
            IVagonService vagonService = ServiceManager.getInstance().getVagonService();
            session = sessionFactory.openSession();
            List<Map<String, Long>> selectList = (List<Map<String, Long>>) session.selectList(MAPPER + SQL_GET_TRIPVALUES_FOR_VAGON, vaognId);
            for (Map<String, Long> map : selectList) {
                Long tripId = map.get("TRIP_ID");
                TripVO trip = getTrip(tripId);
                if (trip != null) {
                    List<Map<String, Long>> listTripValues = (List<Map<String, Long>>) session.selectList(MAPPER + SQL_GET_TRIPVALUES_FOR_TRIP, trip.getId());
                    List<VagonVO> listVagons = new ArrayList<VagonVO>();
                    for (Map<String, Long> mapVagons : listTripValues) {
                        VagonVO vagon = vagonService.getVagon(mapVagons.get("VAGON_ID"));
                        listVagons.add(vagon);
                    }
                    trip.setListVagons(listVagons);
                    result.add(trip);
                }
            }
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            throw e;
        } finally {
            session.close();
        }
        if (result != null) {
            Collections.sort(result, new Comparator<TripVO>() {
                @Override
                public int compare(TripVO o1, TripVO o2) {
                    return o1.getDateFrom().compareTo(o2.getDateFrom());
                }
            });
        }
        return result;
    }

}
